/***************************************************************************/
/*                                                                         */
/*  ftcglyph.c                                                             */
/*                                                                         */
/*    FreeType Glyph Image (FT_Glyph) cache (body).                        */
/*                                                                         */
/*  Copyright 2000-2001, 2003, 2004, 2006, 2009 by                         */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/


#include <ft2build.h>
#include FT_CACHE_H
#include "ftcglyph.h"
#include FT_ERRORS_H

#include "ftccback.h"
#include "ftcerror.h"


/* create a new chunk node, setting its cache index and ref count */
FT_LOCAL_DEF(void)
FTC_GNode_Init(FTC_GNode gnode,
               FT_UInt gindex,
               FTC_Family family)
{
    gnode->family = family;
    gnode->gindex = gindex;
    family->num_nodes++;
}


FT_LOCAL_DEF(void)
FTC_GNode_UnselectFamily(FTC_GNode gnode,
                         FTC_Cache cache)
{
    FTC_Family family = gnode->family;


    gnode->family = NULL;
    if (family && --family->num_nodes == 0)
        FTC_FAMILY_FREE(family, cache);
}


FT_LOCAL_DEF(void)
FTC_GNode_Done(FTC_GNode gnode,
               FTC_Cache cache)
{
    /* finalize the node */
    gnode->gindex = 0;

    FTC_GNode_UnselectFamily(gnode, cache);
}


FT_LOCAL_DEF(FT_Bool)
ftc_gnode_compare(FTC_Node ftcgnode,
                  FT_Pointer ftcgquery,
                  FTC_Cache cache)
{
    FTC_GNode gnode = (FTC_GNode)ftcgnode;
    FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
    FT_UNUSED(cache);


    return FT_BOOL(gnode->family == gquery->family &&
                   gnode->gindex == gquery->gindex);
}


FT_LOCAL_DEF(FT_Bool)
FTC_GNode_Compare(FTC_GNode gnode,
                  FTC_GQuery gquery)
{
    return ftc_gnode_compare(FTC_NODE(gnode), gquery, NULL);
}


/*************************************************************************/
/*************************************************************************/
/*****                                                               *****/
/*****                      CHUNK SETS                               *****/
/*****                                                               *****/
/*************************************************************************/
/*************************************************************************/

FT_LOCAL_DEF(void)
FTC_Family_Init(FTC_Family family,
                FTC_Cache cache)
{
    FTC_GCacheClass clazz = FTC_CACHE__GCACHE_CLASS(cache);


    family->clazz = clazz->family_class;
    family->num_nodes = 0;
    family->cache = cache;
}


FT_LOCAL_DEF(FT_Error)
ftc_gcache_init(FTC_Cache ftccache)
{
    FTC_GCache cache = (FTC_GCache)ftccache;
    FT_Error error;


    error = FTC_Cache_Init(FTC_CACHE(cache));
    if (!error)
    {
        FTC_GCacheClass clazz = (FTC_GCacheClass)FTC_CACHE(cache)->org_class;

        FTC_MruList_Init(&cache->families,
                         clazz->family_class,
                         0, /* no maximum here! */
                         cache,
                         FTC_CACHE(cache)->memory);
    }

    return error;
}


#if 0

FT_LOCAL_DEF(FT_Error)
FTC_GCache_Init(FTC_GCache cache)
{
    return ftc_gcache_init(FTC_CACHE(cache));
}

#endif /* 0 */


FT_LOCAL_DEF(void)
ftc_gcache_done(FTC_Cache ftccache)
{
    FTC_GCache cache = (FTC_GCache)ftccache;


    FTC_Cache_Done((FTC_Cache)cache);
    FTC_MruList_Done(&cache->families);
}


#if 0

FT_LOCAL_DEF(void)
FTC_GCache_Done(FTC_GCache cache)
{
    ftc_gcache_done(FTC_CACHE(cache));
}

#endif /* 0 */


FT_LOCAL_DEF(FT_Error)
FTC_GCache_New(FTC_Manager manager,
               FTC_GCacheClass clazz,
               FTC_GCache * acache)
{
    return FTC_Manager_RegisterCache(manager, (FTC_CacheClass)clazz,
                                     (FTC_Cache*)acache);
}


#ifndef FTC_INLINE

FT_LOCAL_DEF(FT_Error)
FTC_GCache_Lookup(FTC_GCache cache,
                  FT_UInt32 hash,
                  FT_UInt gindex,
                  FTC_GQuery query,
                  FTC_Node * anode)
{
    FT_Error error;


    query->gindex = gindex;

    FTC_MRULIST_LOOKUP(&cache->families, query, query->family, error);
    if (!error)
    {
        FTC_Family family = query->family;


        /* prevent the family from being destroyed too early when an        */
        /* out-of-memory condition occurs during glyph node initialization. */
        family->num_nodes++;

        error = FTC_Cache_Lookup(FTC_CACHE(cache), hash, query, anode);

        if (--family->num_nodes == 0)
            FTC_FAMILY_FREE(family, cache);
    }
    return error;
}

#endif /* !FTC_INLINE */


/* END */